package img;

import org.im4java.core.ConvertCmd;
import org.im4java.core.IMOperation;

import java.io.File;
import java.util.LinkedList;


/**
 * .heic只是HEIF文件格式的一种扩展名，言外之意是：HEIF不仅有.heic这种扩展名，还有其它的，比如说：.heif和.avci，它们都是属于HEIF文件格式。
 * HEIC图片和HEVC视频的文件格式后缀名是.heic、.heif、.avci。
 * HEIF & HEVC 你知道多少？  https://www.sohu.com/a/197929059_208051
 * 在升级 iOS 11 之后，iPhone 7 及更新的设备内的照片存储将不再用 JPEG 了，而采用了一种新的图片格式 HEIF（发音同 heef），
 * 在 iOS 中对应的文件后缀为 .heic ，其编码用的是 HEVC格式，又称 H.265 （这个就很熟悉了 H.264 的下一代），
 * 同时视频也用 HEVC 作为编码器，对应的文件后缀还是 .mov 。
 * 用 HEVC 进行编码的 HEIF 图片就是后缀为 .heic 的图片，也是苹果主要使用的格式。
 * 这两个都是很新的标准，分别在 2015 和 2013 年才被 ISO 批准。
 * HEIF 全称 High Efficiency Image Format（高效图像文件格式）。
 * 是由 Moving Picture Experts Group 制定的，存储图片和图片序列的格式。
 * 相关的介绍位置这边可以看到 nokiatech.github.io/heif/  https://github.com/nokiatech/heif
 * 这种格式通过更高效的压缩算法，能够在保持较高图像质量的同时减小文件大小，从而节省手机存储空间。
 * 然而，HEIC格式并不是所有设备和平台都广泛支持的标准格式，这可能会导致一些兼容性问题
 * 在质量相同甚至略有提高的情况下，以新格式存储的图像所需的存储空间比相应的 JPEG 图像少了约 50-60%。
 *
 * HEIF：你需要知道的关于 HEIF 图像文件格式的所有信息 http://www.dayanzai.me/what-is-a-heif-file.html
 * 如果在社交网络上分享或导出到不支持 HEIF 的旧苹果系统和其他平台（如Windows），.heic 的图像会自动转换为 .jpg。
 * 对于苹果设备用户来说，‌使用设备自带的“照片”应用也是一种选择。‌虽然这种方法适用于单张图片转换，‌但通过点击左下角的“分享”按钮并选择“存储为文件”选项，
 * ‌在弹出的窗口中选择JPG作为输出格式，‌可以方便地将HEIC图片转换为JPEG格式
 *
 * 【heic转换】iPhone中heic图片如何转换成jpg？ https://zhuanlan.zhihu.com/p/665476451
 * 分享到其他平台 可以自动转换为jpeg，但是先打zip压缩包，则不会转换
 * 关闭 iPhone 上的 HEIC 并将 HEIC 照片转换为 JPEG https://www.apeaksoft.com/zh-CN/tips/turn-off-heic-on-iphone.html
 * 在线转换网站：https://heictojpg.com/
 * wps可以查看heic格式的图片，转换图片格式需要会员
 * HEIC图片和HEVC视频文件怎么打开？win10支持此格式解码器方法 https://www.xitmi.com/2085.html
 * ImageMagick是一款免费开源的图片编辑软件。既可以通过命令行使用，也可以通过调用API来完成。
 * https://github.com/ImageMagick/ImageMagick https://hub.nuaa.cf/ImageMagick/ImageMagick
 * http://www.imagemagick.com.cn/download.html
 *
 * https://hub.nuaa.cf/aheckmann/gm
 * http://www.graphicsmagick.org/download.html
 * https://sourceforge.net/projects/graphicsmagick/files/ https://sourceforge.net/projects/graphicsmagick/files/graphicsmagick/1.3.43/
 *
 */
public class HeicToJpegUtil {

    // ImageMagick安装的路径
    // private static final String IMAGE_MAGICK_PATH = "D:\\soft\\ImageMagick-7.1.1-34-portable-Q16-x64";
    // private static final String IMAGE_MAGICK_PATH = "D:\\soft\\ImageMagick-7.1.1-34-portable-Q16-HDRI-x64";
    private static final String IMAGE_MAGICK_PATH = "ImageMagick-7.1.1-34-portable-Q16-HDRI-x64";

    public static void main(String[] args) throws Exception {
        // 要压缩的目录 或文件
        String filePath = "C:\\Users\\74102\\Downloads\\11\\11";

        FileUtil.scanOrHandleFile(filePath, f -> heicToJpeg(f, null));
    }

    /**
     * java调用imagemagick进行图片格式转换，例如heic转成jpg https://blog.csdn.net/weixin_52735964/article/details/126370828
     * 踩坑ImageMagick将ios图片文件HEIC格式转jpg/png等 https://blog.csdn.net/x4789508a/article/details/127545604
     * linux下编译安装imagemagick：how to covert heif to jpg with java https://www.cnblogs.com/zust
     *
     * 现成exe工具
     * Heif/Heic 转 JPG 免费工具 https://blog.csdn.net/cjj730/article/details/104134810 https://github.com/jianjun-chen/Heif2Jpg
     * https://github.com/saschiwy/HeicConverter/releases  heicConverterGui.exe
     */
    public static void heicToJpeg(File file, File outFile) {
        String fileExt = FileUtil.getFileExtWithDoc(file);
        if (fileExt == null || !fileExt.equals(".heic")) {
            System.out.println("非heic文件");
            return;
        }

        if (outFile == null) {
            outFile = getOutFile(file) ;
        }
        if (outFile.exists() && outFile.isFile()) {
            System.out.println("输出文件已存在");
            return;
        }

        /**
         * im4java 是ImageMagick的第二个Java接口实现，它不是 JMagick的替代品，而是作为一个补充。
         * im4java只生成ImageMagick命令的命令行，并将生成的行传递给选中的IM命令(使用java.lang.ProcessBuilder.start()方法)
         * https://blog.csdn.net/nathan_csdn/article/details/126100165
         */
        /**
         * https://www.cnblogs.com/ScofieldBai/p/7881586.html
         * graphicsmagick和imagemagick对比 https://blog.csdn.net/chyunling/article/details/9225985
         * convert|magick：转换图像格式和大小，模糊，裁剪，驱除污点，抖动，临近，图片上画图片，加入新图片，生成缩略图等。
         * identify：描述一个或较多图像文件的格式和特性。
         * mogrify：按规定尺寸*一个图像，模糊，裁剪，抖动等。Mogrify改写最初的图像文件然后写到一个不同的图像文件。
         * composite：根据一个图片或多个图片组合生成图片。
         * montage：创建一些分开的要素图像。在含有要素图像任意的装饰图片，如边框、结构、图片名称等。
         * compare：在算术上和视觉上评估不同的图片*其它的改造图片。
         * display：如果你拥有一个X server的系统，它可以按次序的显示图片
         * animate：利用X server显示动画图片
         * import：在X server或任何可见的窗口上输出图片文件。 你可以捕获单一窗口，整个的荧屏或任何荧屏的矩形部分。
         * conjure：解释执行 MSL (Magick Scripting Language) 写的脚本。
         */
        // 此处会选择是使用ImageMagick，还是GraphicsMagick
        // GraphicsMagick是从 ImageMagick 5.5.2 分支出来的，但是现在他变得更稳定和优秀，GM更小更容易安装
        ConvertCmd cmd = new ConvertCmd();

        /**
         * 免安装版目录下没有convert.exe  只有magick.exe
         * 可以把其他exe都删掉 只保留magick.exe
         */
        LinkedList<String> command = cmd.getCommand();
        if (command != null && command.size() == 1 && "convert".equals(command.get(0))) {
            command.set(0, "magick");
        }

        // windows下才需要设置imageMagick安装地址
        cmd.setSearchPath(IMAGE_MAGICK_PATH);

        // 创建图片操作对象
        IMOperation op = new IMOperation();
        op.addImage(file.getAbsolutePath()); // 需要转换的图片路径 绝对路径
        op.addImage(outFile.getAbsolutePath()); // 转换出来的图片路径

        /**
         * org.im4java.core.CommandException: java.io.FileNotFoundException: convert
         * 解决办法：将目录下的 magick.exe 复制一份，改名为 convert.exe
         */
        // 启动
        try {
            cmd.run(op);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * 获取压缩之后输出的文件路径
     */
    private static File getOutFile(File sourceFile) {
        String parentDirectory = sourceFile.getParent();
        String fileName = sourceFile.getName();
        String fileExt = FileUtil.getFileExtWithDoc(sourceFile);

        // 名称 substring方法不能接受负数作为参数
        String name = fileName.substring(0, fileName.length() - fileExt.length());

        // 输出文件路径
        String outPath = parentDirectory + File.separator + name + ".jpg";;

        File outFile = new File(outPath);
        return outFile;
    }

}

